//Andres Garcia Morro
//Sergio Navarro Perez
//Pablo Pellicer Javier

%{
#include <stdio.h>
//#include "libtds.h"
//#include "libgci.h"
#include "cabecera.h"


int desplGlobal;
int dirMain;

%}

%error-verbose

%union {
	tipo_nom tiponom;
	args_aux argsaux;
	if_str ifstr;
	char *ident;
	int cent;
	int aux;
	int codop;
}

%token <ident> ID_
%token <cent> CTE_
%token MASMAS_ MENOSMENOS_ IGUAL_ MASIGUAL_ MENOSIGUAL_ COMA_
%token INT_  PUNTOYCOMA_
%token PUNTO_ IGUALIGUAL_ DESIGUAL_
%token MENORQUE_ MAYORQUE_ MAYORIGUAL_ MENORIGUAL_ COMEN_
%token STRUCT_ READ_ PRINT_ IF_ ELSE_ FOR_ RETURN_ 
%left MAS_ MENOS_
%left POR_ DIV_
%left CORABR_ CORCER_
%left PARABR_ PARCER_
%left LLAVABR_ LLAVCER_


%type <argsaux> programa;
%type <ifstr>   instruccionSeleccion;
%type <argsaux> instruccionIteracion;


%type <tiponom> tipo
%type <tiponom> declaracionVariable
%type <tiponom> expresionOpcional
%type <tiponom> expresion
%type <tiponom> expresionIgualdad
%type <tiponom> expresionRelacional
%type <tiponom> expresionAditiva
%type <tiponom> expresionMultiplicativa
%type <tiponom> expresionUnaria
%type <tiponom> expresionSufija
%type <tiponom> listaCampos
%type <tiponom> listaParametrosFormales
%type <tiponom> listaParametrosActuales
%type <tiponom> parametrosFormales
%type <tiponom> parametrosActuales
%type <tiponom> declaracionVariableLocal

%type <aux>	cabeceraFuncion
%type <aux>	instruccion
%type <aux>	bloque;

%type <codop> operadorAsignacion
%type <codop> operadorIgualdad 
%type <codop> operadorRelacional
%type <codop> operadorAditivo
%type <codop> operadorMultiplicativo
%type <codop> operadorIncremento
%type <codop> operadorUnario


%%
programa : 	{ 
		  numErrores=0;
		  dvar=0; nivel=0; si=0; cargaContexto(nivel);
		  // Incrementaremos la pila en el desplazamiento de las variables globales 
		  desplGlobal = creaLans(si);
		  emite(INCTOP, crArgNulo(), crArgNulo(), crArgNulo());

		  dirMain = creaLans(si);
		  emite(GOTOS, crArgNulo(), crArgNulo(), crArgNulo());
		}

		secuenciaDeclaraciones

		{ 
		  SIMB sim;
		  //TIPO_ARG res;
		  sim = obtenerSimbolo("main");
		  if (sim.categoria != FUNCION){
			yyerror("No existe la funcion main");
		  }
		  else{
			
			// Ponemos la direccion del main
			completaLans(dirMain, crArgEtiqueta(sim.desp));
			// Completamos la instrucción con dvar
			completaLans(desplGlobal, crArgEntero(dvar));
			if(verTDS) mostrarTDS(0);
			  descargaContexto(nivel);	
			  vuelcaCodigo(nombrefichero);
		  }
		};

secuenciaDeclaraciones :  declaracion 
			| secuenciaDeclaraciones declaracion;

declaracion : 	  
		declaracionVariable 
			{ if(!insertaSimbolo($1.nombre, VARIABLE, $1.tipo, dvar, nivel, $1.ref)){
				char cadena[100]; sprintf(cadena,"El identificador '%s' esta repetido",$1.nombre);
				yyerror(cadena);
			  }
			  dvar += $1.talla; // En else?
			  if (verTDS) mostrarTDS(nivel);
			}
		| declaracionFuncion;

declaracionVariable : 	  
		tipo ID_ PUNTOYCOMA_ 
			{ $$.nombre = $2;
			  $$.tipo   = $1.tipo;
			  $$.talla  = $1.talla;
			  $$.ref    = $1.ref;
			}
		| tipo ID_ CORABR_ CTE_ CORCER_ PUNTOYCOMA_
			{
			  // Comprobaciones
			  if($4<=0) yyerror("El tamanyo del vector debe ser mayor que 0");
			  if($1.tipo!=T_ENTERO){
				char cadena[100]; sprintf(cadena,"El array '%s' no es de tipo entero",$2);
				yyerror(cadena);
			  }
		 	  
			  $$.nombre = $2;
			  $$.tipo   = T_ARRAY;
			  $$.ref    = insertaInfoArray($1.tipo,$4);
			  $$.talla  = $1.talla * $4;
			};			
			

tipo : 	        INT_ 
			{ $$.tipo = T_ENTERO;
			  $$.talla = TALLA_ENTERO;
			  $$.ref = -1;
			}
	        | STRUCT_ LLAVABR_ listaCampos LLAVCER_
			{ $$.tipo=T_RECORD;
        		  $$.talla = $3.talla;
			  $$.ref = $3.ref;
			}
			;

listaCampos : 	  declaracionVariable 
			{ if($1.tipo != T_ENTERO){
				char cadena[100];
				sprintf(cadena,"El campo '%s' no es de tipo entero",$1.nombre);
				yyerror(cadena);
			  }
			  else {
				// La referencia es "-1" porque crea una nueva entrada en la tabla de registros
				$$.ref = insertaInfoCampo(-1, $1.nombre, $1.tipo, 0);
			  	$$.talla = $1.talla;	// TALLA_ENTERO, porque no puede ser de otro tipo
				$$.tipo = $1.tipo;
			  }
			}
		| listaCampos declaracionVariable
			{ if($2.tipo != T_ENTERO){
				char cadena[100];
				sprintf(cadena,"El campo '%s' no es de tipo entero",$2.nombre);
				yyerror(cadena);
			  }
			  // Desplazamiento = talla de los elementos anteriores
			  else {
				$$.ref = insertaInfoCampo($1.ref, $2.nombre, $2.tipo, $1.talla);
				if ($$.ref == -1){
					char cadena[100];
					sprintf(cadena,"El campo '%s' esta repetido",$2.nombre);
					yyerror(cadena);
				}// talla actual = talla anterior + talla del nuevo elemento (se incrementará en 1 porque sólo pueden ser enteros)
			 	else $$.talla = $1.talla + $2.talla;
			  }  
			}
			;


declaracionFuncion : 	cabeceraFuncion
				{ $<aux>$=dvar;
			  	  dvar=0;
				}	
			bloque 
				{ 
				  descargaContexto(nivel);
				  nivel--;
				  dvar=$<aux>2;
				};
 
// El valor semántico de cabeceraFuncion sirve para almacenar la antigua dvar
cabeceraFuncion : tipo ID_ 
			{ dpar=TALLA_SEGENLACES;
			  nivel++;
			  cargaContexto(nivel);
			  if($1.tipo!=T_ENTERO){
			  	char cadena[100]; sprintf(cadena,"La funcion '%s' no es de tipo entero",$2);
				yyerror(cadena);
			  }
			}  
		  PARABR_ parametrosFormales PARCER_ 
			{ //  METER LA FUNCION EN LA TDS. ESE 0 DEBERÍA SER SIGINST
				if(!insertaSimbolo($2, FUNCION, $1.tipo, si, nivel-1, $5.ref)){
					char cadena[100]; sprintf(cadena,"La funcion '%s' tiene un nombre repetido",$2);

					yyerror(cadena);
				}else{
					if(verTDS) mostrarTDS(nivel);
					
				}
			};

parametrosFormales : 	{ $$.tipo = T_VACIO;
			  $$.ref = insertaInfoDominio(-1,T_VACIO);
			}
			| listaParametrosFormales
			{ $$.tipo = $1.tipo;
			  $$.ref  = $1.ref;
			};

listaParametrosFormales : tipo ID_ 
				{if($1.tipo!=T_ENTERO){
				   yyerror("Los parametros solo pueden ser enteros");
				 }else{ 
                                    dpar += $1.talla;
                                    if(!insertaSimbolo($2, PARAMETRO, $1.tipo, -dpar, nivel, $1.ref)){
					char cadena[100]; sprintf(cadena,"Identificador '%s' repetido",$2);
					yyerror(cadena);
				     }
                                     else{
					$$.nombre = $2;
					$$.tipo = $1.tipo;
					$$.talla = $1.talla;
					// ref a -1 para crear una nueva entrada
					$$.ref = insertaInfoDominio(-1,$1.tipo);
					//if (verTDS) mostrarTDS(nivel);
				     }
                                  }
				}

			| tipo ID_ COMA_ 
                                {
                                  if($1.tipo!=T_ENTERO){
                                        yyerror("Los parametros solo pueden ser enteros");
                                  }else{
					dpar += $1.talla;
					if(!insertaSimbolo($2, PARAMETRO, $1.tipo, -dpar, nivel, $1.ref)){
                                       		char cadena[100]; sprintf(cadena,"Identificador '%s' repetido",$2);
                                       		yyerror(cadena);
                                  	}
				  }
                                } listaParametrosFormales
				{ if($1.tipo!=T_ENTERO){
				  	yyerror("Los parametros solo pueden ser enteros");
				  }else{  
					$$.nombre = $2;
					$$.tipo = $1.tipo;
					$$.talla = $1.talla;
					$$.ref = insertaInfoDominio($5.ref,$1.tipo);
					//if (verTDS) mostrarTDS(nivel);
				  }
				};


bloque : 	{
		  emite(PUSHFP, crArgNulo(), crArgNulo(), crArgNulo());
		  emite(FPTOP, crArgNulo(), crArgNulo(), crArgNulo());
		  $<aux>$ = creaLans(si);
		  emite(INCTOP, crArgNulo(), crArgNulo(), crArgNulo());
		}
	LLAVABR_ declaracionVariableLocal listaInstrucciones LLAVCER_
		{ completaLans($<aux>1, crArgEntero(dvar));

		  emite(TOPFP, crArgNulo(), crArgNulo(), crArgNulo());
		  emite(FPPOP, crArgNulo(), crArgNulo(), crArgNulo());

		  // A la hora de devolver, comprobamos si es main o no
		  INF info = obtenerInfoFuncion(-1);
		  if (strcmp(info.nombre, "main")){  // La funcion no es main
			emite(RET, crArgNulo(), crArgNulo(), crArgNulo());
		  }else{
			emite(FIN, crArgNulo(), crArgNulo(), crArgNulo());
		  }
		};

declaracionVariableLocal :  {} 
			| declaracionVariableLocal declaracionVariable
				{
				  if(!insertaSimbolo($2.nombre, VARIABLE, $2.tipo, dvar, nivel, $2.ref)){
					char cadena[100]; sprintf(cadena,"El identificador '%s' esta repetido",$2.nombre);
					yyerror(cadena);
		 		  }
		 		  dvar += $2.talla; // En else?
				  if (verTDS) mostrarTDS(nivel);
				}
			;

listaInstrucciones : {} 
		 | listaInstrucciones instruccion {};

instruccion : 		{nivel++; cargaContexto(nivel); $<aux>$ = dpar;}
			LLAVABR_ declaracionVariableLocal listaInstrucciones LLAVCER_ 
			{descargaContexto(nivel); nivel--; dpar = $<aux>$;}
			| instruccionExpresion  {}
			| instruccionEntradaSalida {} 
			| instruccionSeleccion {}
			| instruccionIteracion {}
			| instruccionSalto {};

instruccionExpresion : 	  PUNTOYCOMA_ 
			| expresion PUNTOYCOMA_;
	
instruccionEntradaSalida :	PRINT_ PARABR_ expresion 
					{if($3.tipo != T_ENTERO) {
						char cadena[100];
						sprintf(cadena,"La expresion no es de tipo entero (PRINT)");
						yyerror(cadena);
					}else{
					   emite(EWRITE, crArgNulo(), crArgNulo(), $3.pos);
					 }
				}PARCER_ PUNTOYCOMA_ 
				| READ_ PARABR_ ID_ PARCER_ PUNTOYCOMA_
					{ SIMB sim;	
				  	  sim = obtenerSimbolo($3);
				  	  if (sim.categoria == NULO){
						char cadena[100];
						sprintf(cadena,"Identificador '%s' no declarado (READ)",$3);
						yyerror(cadena);
				  	  }else if(sim.tipo != T_ENTERO) {
						char cadena[100];
						sprintf(cadena,"Identificador '%s' no es de tipo entero (READ)",$3);
						yyerror(cadena);
					  }
        				  emite(EREAD,crArgNulo(),crArgNulo(),crArgPosicion(sim.nivel,sim.desp));    
					};
	
instruccionSeleccion : IF_ PARABR_ expresion 
			{ if($3.tipo!=T_LOGICO) yyerror("La condicion del if ha de ser de tipo logico");
			  $<ifstr>$.altern=creaLans(si);
			  emite(EIGUAL, $3.pos, crArgEntero(0), crArgNulo());
			}
			PARCER_ instruccion
			{
			  $<ifstr>$.fin = creaLans(si);
			  emite(GOTOS, crArgNulo(), crArgNulo(), crArgNulo());
			  completaLans($<ifstr>4.altern,crArgEtiqueta(si));
			}
			ELSE_ instruccion
			{
			 completaLans($<ifstr>7.fin,crArgEtiqueta(si));
			};
                         
	

instruccionIteracion : FOR_ PARABR_ expresionOpcional 
				{
				  if ($3.tipo == T_ERROR){
					yyerror("Error de tipos en la primera expresion del for");
			  	  }
				  $<argsaux>$.cond=si;
				} 
			PUNTOYCOMA_ expresion 
				{
				  if ($6.tipo != T_LOGICO){
					yyerror("La expresion central del for no es de tipo logico");
				  }
				  $<argsaux>$.fin=creaLans(si);
				  emite(EIGUAL, $6.pos, crArgEntero(0), crArgNulo());
				 /* if($6.ref==VERDADERO){
					//$<argsaux>$.fin = creaLans(si);
					emite(GOTOS,crArgNulo(),crArgNulo(),crArgNulo());
				  }*/
				  $<argsaux>$.cuerpo=creaLans(si);
				  emite(GOTOS,crArgNulo(),crArgNulo(),crArgNulo());
				  $<argsaux>$.incr=si;
				} 
			PUNTOYCOMA_ expresionOpcional 
				{
				  if ($9.tipo == T_ERROR){
					yyerror("Error de tipos en la ultima expresion del for");
			  	  }
				  emite(GOTOS,crArgNulo(),crArgNulo(),crArgEtiqueta($<argsaux>4.cond));
				  completaLans($<argsaux>7.cuerpo,crArgEtiqueta(si));
				}
			PARCER_ instruccion
				{
				  emite(GOTOS,crArgNulo(),crArgNulo(),crArgEtiqueta($<argsaux>7.incr));
				  completaLans($<argsaux>7.fin,crArgEtiqueta(si));
				};


expresionOpcional :   				{$$.tipo = T_VACIO;}
			| expresion		{$$ = $1;};
	

instruccionSalto : RETURN_ expresion PUNTOYCOMA_
			{
			  INF info = obtenerInfoFuncion(-1);
			  if ($2.tipo != info.tipo)
				yyerror("Error de tipos en el return. El tipo no coincide con el de la funcion");
			  // TALLA_ENTERO es 1. Si pudiera ser de otro tipo, toca cambiar
			  emite(EASIG, $2.pos, crArgNulo(), crArgPosicion(nivel, -(info.tparam + TALLA_SEGENLACES + TALLA_ENTERO)));
			};
	
expresion : 	  expresionIgualdad 
			{
			  $$ = $1;
			}
		| ID_ operadorAsignacion expresion 
			// Si los dos lados son de tipo entero, OK. Si no, error.
			{ SIMB sim;
			  sim = obtenerSimbolo($1);
			  if (sim.categoria == NULO){
				char cadena[100];
				sprintf(cadena,"Identificador '%s' no declarado",$1);
				yyerror(cadena);
			  }
			  if ((sim.tipo==$3.tipo)&&(sim.tipo==T_ENTERO)){
				$$.tipo=T_ENTERO;
				if($2==ESUM){
					$$.pos = crArgPosicion(sim.nivel, sim.desp);
					emite(ESUM,$$.pos,$3.pos,$$.pos);
				}else if ($2==EDIF){
					$$.pos = crArgPosicion(sim.nivel, sim.desp);
					emite(EDIF,$$.pos,$3.pos,$$.pos);
				}else if ($2==EASIG){
					$$.pos = crArgPosicion(sim.nivel, sim.desp);
					emite(EASIG,$3.pos,crArgNulo(),$$.pos);
				}	
			  }
			  else{
			  	if(($3.tipo!=T_ERROR)&&(sim.tipo!=T_ERROR))
				  yyerror("Error de tipos en la expresion de asignacion");
				$$.tipo=T_ERROR;
			  }
			}
		| ID_ CORABR_ expresion CORCER_ operadorAsignacion expresion 
			{
			  SIMB sim;
			  DIM dimen;
			  sim = obtenerSimbolo($1);
			  if (sim.categoria == NULO){
				char cadena[100];
				sprintf(cadena,"Identificador '%s' no declarado",$1);
				yyerror(cadena);
				$$.tipo = T_ERROR;
			  } else if (sim.tipo != T_ARRAY){
				char cadena[100];
				sprintf(cadena,"La variable '%s' no es un array",$1);
				yyerror(cadena);
				$$.tipo = T_ERROR;
			  }else{
			  	dimen = obtenerInfoArray(sim.ref);
					if ($3.tipo != T_ENTERO){
						yyerror("El indice del vector debe ser un entero");
						$$.tipo = T_ERROR;
			 		}else{
			  			if ((dimen.telem == T_ENTERO)&&($6.tipo == T_ENTERO)){
							$$.tipo=T_ENTERO;
							TIPO_ARG aux = crArgPosicion(sim.nivel, sim.desp);
							if($5 == EASIG){
								emite(EVA,aux,$3.pos,$6.pos);
								$$.pos = $6.pos;
							}
							else{ // Para += y -=
								$$.pos = crArgPosicion(nivel,creaVarTemp());
								emite(EAV,aux,$3.pos,$$.pos);  // Cogemos el elemento del vector
								emite($5,$$.pos,$6.pos,$$.pos);// Lo sumamos/restamos
								emite(EVA,aux,$3.pos,$$.pos);  // Y lo reasignamos
							}
						}
			 			if ($6.tipo!=T_ENTERO){
							yyerror("Error de tipos en la expresion de asignacion");
							$$.tipo=T_ERROR;
						}
					}
			  }
			}
		| ID_ PUNTO_ ID_ operadorAsignacion expresion 
			{
			  SIMB sim;
			  REG regi;
			  sim = obtenerSimbolo($1);
			  if (sim.categoria == NULO) {
				char cadena[100]; sprintf(cadena,"Identificador '%s' no declarado",$1);
				yyerror(cadena);
				$$.tipo = T_ERROR;
			  }
			  else if (sim.tipo != T_RECORD){
				char cadena[100];
				sprintf(cadena,"La variable '%s' no es una estructura",$1);
				yyerror(cadena);
				$$.tipo = T_ERROR;
			  } else{
				regi = obtenerInfoCampo(sim.ref, $3);
				if(regi.tipo == T_ERROR){
					char cadena[100]; sprintf(cadena,"La estructura '%s' no contiene el campo '%s'",$1,$3);
					yyerror(cadena);
					$$.tipo=T_ERROR;
				}
				if((regi.tipo==T_ENTERO)&&($5.tipo==T_ENTERO))
				{
					$$.tipo=T_ENTERO;
					$$.pos = crArgPosicion(sim.nivel, (sim.desp+regi.desp));
					if($4 == EASIG){
						emite(EASIG,$5.pos,crArgNulo(),$$.pos);
					}else{	// Para -= o += ||| a.c1 -= x --> a.c1 = a.c1 - x
						emite($4,$$.pos,$5.pos,$$.pos);
					}
				}
				else{
					if((regi.tipo!=T_ERROR)&&($5.tipo!=T_ERROR)){
						yyerror("Error de tipos en la expresion de asignacion");
						$$.tipo=T_ERROR;
					}
				}
			  }		  
			};
	
expresionIgualdad : 	 expresionRelacional 	{$$ = $1;}
			| expresionIgualdad operadorIgualdad expresionRelacional			
				{ if (($1.tipo == T_ENTERO) && ($3.tipo == T_ENTERO))
				  {
					$$.tipo = T_LOGICO;
					// Partimos de valor de verdad = VERDADERO
					$$.pos = crArgPosicion(nivel,creaVarTemp());
					emite(EASIG,crArgEntero(VERDADERO),crArgNulo(),$$.pos);
					// Si se cumple, nos saltamos la puesta a FALSO
					emite($2,$1.pos,$3.pos,crArgEtiqueta(si+2));
					// Si no, ponemos a FALSO
					emite(EASIG,crArgEntero(FALSO),crArgNulo(),$$.pos);
				  }else{
					yyerror ("Error de tipos en la expresion de igualdad");
					$$.tipo=T_ERROR;
				  }
				};
		
expresionRelacional : 	  expresionAditiva   	{$$ = $1;} 
			| expresionRelacional operadorRelacional expresionAditiva
				{ if (($1.tipo == T_ENTERO) && ($3.tipo == T_ENTERO))
				  {
					$$.tipo = T_LOGICO;
					// Partimos de valor de verdad = VERDADERO
					$$.pos = crArgPosicion(nivel,creaVarTemp());
					emite(EASIG,crArgEntero(VERDADERO),crArgNulo(),$$.pos);
					// Si se cumple, nos saltamos la puesta a FALSO
					emite($2,$1.pos,$3.pos,crArgEtiqueta(si+2));
					// Si no, ponemos a FALSO
					emite(EASIG,crArgEntero(FALSO),crArgNulo(),$$.pos);
				  }
				  else{
					yyerror ("Error de tipos en la expresion relacional");
					$$.tipo=T_ERROR;
				  }
				};
			
expresionAditiva : 	  expresionMultiplicativa 			{$$ = $1;}
			| expresionAditiva operadorAditivo expresionMultiplicativa
				{ if (($1.tipo == T_ENTERO) && ($3.tipo == T_ENTERO)) 
				  {
					$$.tipo = T_ENTERO;
					$$.pos = crArgPosicion(nivel, creaVarTemp());
					emite($2,$1.pos,$3.pos,$$.pos);
				  }
				  else{
					yyerror ("Error de tipos en la expresion aditiva");
					$$.tipo=T_ERROR;
				  }
				};
		
expresionMultiplicativa : 	  expresionUnaria 				{$$ = $1;}
			| expresionMultiplicativa operadorMultiplicativo expresionUnaria
				{ if (($1.tipo == T_ENTERO) && ($3.tipo == T_ENTERO))
				  { $$.tipo = T_ENTERO;
				    $$.pos = crArgPosicion(nivel,creaVarTemp());
				    emite($2,$1.pos,$3.pos,$$.pos);
				  }
				  else{
					yyerror ("Error de tipos en la expresion multiplicativa");
					$$.tipo=T_ERROR;
				  }
				};
		
expresionUnaria : 	  expresionSufija 				{ $$ = $1; }
			| operadorUnario expresionUnaria 		
				{ $$.tipo = $2.tipo;
           			  if($1==EDIF){
				  	// Si el signo es -, cambiar el valor de $2 y guardarlo en $$
					$$.pos = crArgPosicion(nivel, creaVarTemp());
				  	emite(ESIG,$2.pos,crArgNulo(),$$.pos);
				  }else $$ = $2;
        			}
			| operadorIncremento ID_     
				{ 
				  SIMB sim;
				  TIPO_ARG res;
				  sim = obtenerSimbolo($2);
				  if (sim.categoria == NULO || sim.categoria == FUNCION) {
				  	char cadena[100];
					sprintf(cadena,"El identificador '%s' no es una variable",$2);
				  	yyerror(cadena);
				 	$$.tipo = T_ERROR;
			 	  }else{
					if(sim.tipo != T_ENTERO){
						char cadena[100]; sprintf(cadena,"La variable '%s' no es un entero",$2);
						yyerror(cadena);
					}else{
				 		$$.nombre = $2;
				 		$$.ref = sim.ref;
						if(sim.tipo == T_ENTERO) $$.talla = TALLA_ENTERO;
						$$.tipo = sim.tipo;

						res = crArgPosicion(sim.nivel, sim.desp);
						$$.pos = crArgPosicion(nivel, creaVarTemp());
						emite($1,res,crArgEntero(1),res);
						emite(EASIG,res,crArgNulo(),$$.pos);
					}
				  }
				};
	
expresionSufija : 	  ID_ CORABR_ expresion CORCER_ 		
				{ SIMB sim;
				  DIM  dimen;
				  sim = obtenerSimbolo($1);
				  if (sim.categoria == NULO) {
				  	char cadena[100];
					sprintf(cadena,"Identificador '%s' no declarado",$1);
				  	yyerror(cadena);
				 	$$.tipo = T_ERROR;
			 	  }else if (sim.tipo != T_ARRAY){
					char cadena[100];
					sprintf(cadena,"La variable '%s' no es un array",$1);
					yyerror(cadena);
					$$.tipo = T_ERROR;
			 	  }else{
				  	if($3.tipo == T_ENTERO){
						dimen = obtenerInfoArray(sim.ref);
						$$.tipo = dimen.telem;
						$$.pos = crArgPosicion(nivel,creaVarTemp());
						emite(EAV, crArgPosicion(sim.nivel,sim.desp), $3.pos, $$.pos);
					}else{
						yyerror("El indice del vector debe ser un entero");
						$$.tipo = T_ERROR;
					}
				  }
				}
			| ID_ PUNTO_ ID_ 
				{ SIMB sim;
				  REG regi;
				  sim = obtenerSimbolo($1);
				  if(sim.categoria == NULO){
				  	char cadena[100];
					sprintf(cadena,"Identificador '%s' no declarado",$1);
				  	yyerror(cadena);
				 	$$.tipo = T_ERROR;
				  }else if(sim.tipo!=T_RECORD){
				  	char cadena[100];
					sprintf(cadena,"La variable '%s' no es una estructura",$1);
					yyerror(cadena);
					$$.tipo = T_ERROR;
				  }else{
					regi = obtenerInfoCampo(sim.ref, $3);
					if(regi.tipo == T_ERROR){
						char cadena[100]; sprintf(cadena,"La estructura '%s' no contiene el campo '%s'", $1,$3);
						yyerror(cadena);
						$$.tipo=T_ERROR;
					}else{
						$$.tipo = regi.tipo;
						$$.pos = crArgPosicion(sim.nivel, (sim.desp+regi.desp));
					}
				  }
				}
				 
			| ID_ operadorIncremento			
				{ 
				  SIMB sim;
				  TIPO_ARG res;
				  sim = obtenerSimbolo($1);
				  if (sim.categoria == NULO || sim.categoria == FUNCION) {
				  	char cadena[100];
					sprintf(cadena,"El identificador '%s' no es una variable",$1);
				  	yyerror(cadena);
				 	$$.tipo = T_ERROR;
			 	  }else{
					if(sim.tipo != T_ENTERO){
						char cadena[100]; sprintf(cadena,"La variable '%s' no es un entero",$1);
						yyerror(cadena);
					}else{
				 		$$.nombre = $1;
				 		$$.ref = sim.ref;
						if(sim.tipo == T_ENTERO) $$.talla = TALLA_ENTERO;
						$$.tipo = sim.tipo;

						res = crArgPosicion(sim.nivel, sim.desp);
						$$.pos = crArgPosicion(nivel, creaVarTemp());
						emite(EASIG,res,crArgNulo(),$$.pos);
						emite($2,res,crArgEntero(1),res);

					}
				  }
				}
			| ID_ 
                                {
					// Si las funciones pudieran ser de otro tipo, se debería comprobar la talla antes de incr.
					// No comprueba el tipo de la función porque no puede existir si no es de tipo entero
					emite(INCTOP, crArgNulo(), crArgNulo(), crArgEntero(TALLA_ENTERO));
                                }

                                  PARABR_ parametrosActuales PARCER_	
				{
				  SIMB sim;
				  INF info;

				  sim = obtenerSimbolo($1);
				  info = obtenerInfoFuncion(sim.ref);

				  if(sim.categoria != FUNCION){
				  	char cadena[100];
					sprintf(cadena,"Funcion '%s' no declarada",$1);
				  	yyerror(cadena);
				 	$$.tipo = T_ERROR;
				  }else{  
					if (comparaDominio(sim.ref,$4.ref)){
						// Todo OK, toca llamar a la función

						$$.pos = crArgPosicion(nivel,creaVarTemp());

						$$.tipo = info.tipo;
						$$.talla = info.tparam;
						$$.pos = crArgPosicion(nivel,creaVarTemp());
						emite(CALL,crArgNulo(),crArgNulo(),crArgEtiqueta(sim.desp));
						emite(DECTOP, crArgNulo(), crArgNulo(), crArgEntero(info.tparam));
						emite(EPOP, crArgNulo(), crArgNulo(), $$.pos);
					}else{
						char cadena[100]; sprintf(cadena,"Argumentos erroneos en la invocacion a '%s'",$1);
						yyerror(cadena);
						$$.tipo = T_ERROR;
					}
				  }
				}				 
			| PARABR_ expresion PARCER_ 			{ $$ = $2 }
			| ID_ 						
				{ 
				  SIMB sim;
				  sim = obtenerSimbolo($1);
				  if (sim.categoria == NULO) {
					char cadena[100];
					sprintf(cadena,"Identificador '%s' no declarado",$1);
				  	yyerror(cadena);
				 	$$.tipo = T_ERROR;
			 	  }else{
				  	$$.tipo = sim.tipo;
				 	$$.nombre = $1;
					$$.ref = sim.ref;
				 	if (sim.tipo == T_ENTERO){
						$$.talla = TALLA_ENTERO;
				  		$$.pos = crArgPosicion(sim.nivel, sim.desp);
					}
				 	else {
						char cadena[100]; sprintf(cadena,"'%s' no se trata de una variable entera",$1);
						yyerror(cadena);
						$$.tipo=T_ERROR;
					}
				  }
				}
			| CTE_	 
				{ $$.tipo = T_ENTERO;
				  $$.talla = TALLA_ENTERO;
			  	  $$.ref = -1;
				  $$.pos = crArgPosicion(nivel, creaVarTemp());
				  emite(EASIG, crArgEntero($1), crArgNulo(), $$.pos);
				};

// Esto de los parámetros al llamar a una función suena complicado.
parametrosActuales : 	{ $$.tipo = T_VACIO;
			  $$.ref = insertaInfoDominio(-1,T_VACIO);
			}
			| listaParametrosActuales
			{ $$.tipo = $1.tipo;
			  $$.ref = $$.ref;
			};
	
listaParametrosActuales : 	  expresion 
				{
				  $$.ref = insertaInfoDominio(-1,$1.tipo);
				  emite(EPUSH, crArgNulo(), crArgNulo(), $1.pos);
				}
				| expresion COMA_ listaParametrosActuales
				{ $$.ref = insertaInfoDominio($3.ref, $1.tipo);
				  emite(EPUSH, crArgNulo(), crArgNulo(), $1.pos);
				};


operadorAsignacion : 	  IGUAL_  {$$ = EASIG;}
			| MASIGUAL_ {$$ = ESUM;}
			| MENOSIGUAL_ {$$ = EDIF;};
		
operadorIgualdad : 	  IGUALIGUAL_ {$$ = EIGUAL;}
			| DESIGUAL_ {$$ = EDIST;};
			
operadorRelacional :	  MAYORQUE_ {$$ = EMAY;}
			| MENORQUE_ {$$ = EMEN;}
			| MAYORIGUAL_ {$$ = EMAYEQ;} 
			| MENORIGUAL_ {$$ = EMENEQ;};

operadorAditivo : MAS_ {$$ = ESUM;}
		| MENOS_ {$$ = EDIF;};
	
operadorMultiplicativo :  POR_ {$$ = EMULT;}
			| DIV_ {$$ = EDIVI;};
	
operadorIncremento :      MASMAS_ {$$ = ESUM;}
			| MENOSMENOS_ {$$ = EDIF;};
		
operadorUnario :  MAS_ {$$ = ESUM;}
		| MENOS_ {$$ = EDIF;};
%%
/* Llamada por yyparse ante un error */
yyerror (char *s){
	printf ("Error en Linea %d: %s\n", yylineno, s);
	numErrores++;
}

/*int main (int argc, char **argv){
	if ((yyin = fopen (argv[1], "r")) == NULL)
	fprintf (stderr, "Fichero no valido \%s", argv[1]);
	yyparse();
}*/

int main (int argc, char **argv){
	int i, n = 0;
	verbosidad = verTDS = FALSO;
	for(i=0; i<argc; ++i){
		if(strcmp(argv[i], "-v")==0) 		{ verbosidad = VERDADERO; n++; }
		else if (strcmp(argv[i], "-t")==0)	{ verTDS = VERDADERO; n++; }
	}
	--argc; n++;
	if (argc == n){
		if((yyin = fopen(argv[argc],"r")) == NULL)
			fprintf(stderr, "Fichero no valido: %s\n", argv[argc]);
		else{
			if(verbosidad==VERDADERO) fprintf(stdout, "%3d.-", yylineno);
			strcpy(nombrefichero,argv[argc]);
			yyparse();
			if (numErrores > 0)
				fprintf(stdout,"\nNumero de errores:	%d\n",numErrores);
		}
	}
	else fprintf(stderr, "Uso: cmc [-v] [-t] fichero\n");
}


